#include "servernetengine.h"

#include "netmsg.h"

#include "connectmsg.h"
#include "connectreplymsg.h"
#include "pluginmanager.h"

#include <QDebug>
#include <QTcpSocket>


CServerNetEngine::CServerNetEngine(int nSocketDescriptor, QObject *pParent/* = NULL*/)
	: QThread(pParent),
	  m_nSocketDescriptor(nSocketDescriptor),
	  m_pSocket(NULL)
{

}

void CServerNetEngine::run()
{
	m_pSocket = new QTcpSocket; // If we give this a parent of "this", Qt will bitch at us.
	// I'm not sure I understand why that's a problem, but I would guess it's because the
	// parent is be expected to clean-up it's children, which, as it's in the destructor
	// of this QThread object, could actually run on a separate thread to where the object
	// was created.

	// Attach the socket to the socketDescriptor given to us by our creator.
	// This is the only way we can pass sockets across threads.
	if(!m_pSocket->setSocketDescriptor(m_nSocketDescriptor))
	{
		// TODO: Error handling.
		return;
	}

	// Signals & Slots.
	connect(m_pSocket, SIGNAL(disconnected()), this, SLOT(quit()));
	connect(m_pSocket, SIGNAL(readyRead()), this, SLOT(onData()));

	// here's where the FSM happens. Since there are multiple paths, including at least two large branches,
	// it might be a good idea in the future to make a private utility class to do all the actual work - after we
	// know which option the client is after. THat is, the basic connection & authentication can be made here, and
	// the actual work can be done in a utility class. For now however, I just want to get it going, so I'll dump it all
	// in this file.

	//
	// the network protocol is fairly simple - the connection we're given has been initialised by the client-side, and we
	// should be able to read a connection message straight away. We reply with a reply message, that will tell the client
	// if we accept the incoming connection. If we don't accept the connection, we'll always send a string to the client
	// telling it why. If OTOH we do accept the connection then we'll send the entire plugin config data, as well as any
	// pre-canned config sets.
	//
	// The next message we expect will determine which mode we're in. For now, we only support "project" mode - in this mode
	// the client sends us some source code and some settings, and we send back the project results. So the next message
	// should contain the configured settings, as well as the entire source code set. We'll need to write the source code to a
	// temporary folder on disk, save the settings XML to disk, and create a project class object and point it at the settings
	// and code. While that's running we'll periodically send status updates messages back to the client - telling the client
	// which file we're processing migth be a good idea, along with any other status messages.
	// Once the project class object has been completed, we grab the results file from disk, and send it to the client.
	//
	// That's it! we can now close the connection - the client will have to re-open the connectrion to do anything else with us.
	//
	//
	// A few notes: This is kind of crap - for one thing, the connection is left open, and this FSM will remain in a hanging state
	// while the user selects the project settings in the client UI. A much better approach would be to split the protocol into
	// two or more different runs - where the first run would be (from a client point of view):
	//
	// connect -> get config data -> disconnect.
	//
	// the second run would be:
	//
	// connect -> send source and config data -> recieve status messges -> recieve results -> disconnect.
	//
	// Maybe that's the way to go?
	//
	// - Thomi

	exec();

	// Cleanup here so we're deleting from the thread we created on.
	delete m_pSocket;
}

void CServerNetEngine::onData()
{
	qDebug("onData()");

	CNetMsg *pMsg =0;

	QDataStream ds(m_pSocket);
	QString strError;
	pMsg = CNetMsg::getMsg(ds, &strError);

	if (pMsg)
	{
		switch (pMsg->getType())
		{
			// clients wants to connect to us and get the default config:
			case CNetMsg::MSG_TYPE_CONNECT:
			{
				onClientConnect(static_cast<CConnectMsg*>(pMsg));
			}
			break;
			default:
			{
				qDebug() << "Unknown message type:" << pMsg->getType();
			}
			break;
		}
	}


	delete pMsg;
}


void CServerNetEngine::onClientConnect(CConnectMsg *pMsg)
{
	qDebug() << "Connection from user" << pMsg->getUsername() << "Password is:" << pMsg->getPassword();

	CConnectReplyMsg m;
	m.setConnectionAccepted(true);
	m.setConfigPayload(CPluginManager::getPluginManager()->getPluginConfig());

	qDebug() << "Accepting connection";

	QString strError;
	QDataStream ds(m_pSocket);

	if (!m.setMsg(ds, &strError))
	{
		qDebug() << strError;
	}
}
